/* =============================================================
 * h5_city_picker.js v1.1.0
 * =============================================================
 * Original written by Ysy
 * =============================================================
 * Date 20/05/2020
 * ============================================================ */

(function (factory) {
    "use strict";
    if (typeof define === 'function' && define.amd) {
        define(['jquery'], factory);
    } else {
        factory(jQuery);
    }
}(function ($) {

    let H5CityPicker = function (element, options) {

        if (options == "clear"){
            alert($.fn.h5CityPicker.defaults.type);
            return false;
        }
        this.index = 0;
        this.value = [0, 0, 0];

        this.options = $.extend({}, $.fn.h5CityPicker.defaults, options);
        this.source = this.options.source;
        this.$element = $(element);
        this.$main = $(this.options.main);
        this.data = [];
        this.afterSelect = this.options.afterSelect;
        this.listen();
        // 直接调用
        if (this.options.direct) {
            this.init();
        }
        this.initValue(options);
    };

    H5CityPicker.prototype = {

        constructor: H5CityPicker,

        render: function (data) {
            $("body").append(this.$main);

            var $this = this;

            this.loadData(data, $this);
        },

        init: function () {
            if ($.isFunction(this.source)) {
                this.source($.proxy(this.process, this));
            } else if (this.source) {
                this.render(this.source);
            }
        },

        listen: function () {
            if (!this.options.direct) {
                this.$element
                    .on("click", $.proxy(this.init, this));
            }

            this.$main
                .on("touchstart", ".area_province", $.proxy(this.gearTouchStart, this))
                .on("touchmove", ".area_province", $.proxy(this.gearTouchMove, this))
                .on("touchend", ".area_province", $.proxy(this.gearTouchEnd, this))
                .on("touchstart", ".area_city", $.proxy(this.gearTouchStart, this))
                .on("touchmove", ".area_city", $.proxy(this.gearTouchMove, this))
                .on("touchend", ".area_city", $.proxy(this.gearTouchEnd, this))
                .on("touchstart", ".area_county", $.proxy(this.gearTouchStart, this))
                .on("touchmove", ".area_county", $.proxy(this.gearTouchMove, this))
                .on("touchend", ".area_county", $.proxy(this.gearTouchEnd, this))
                .on("touchstart", ".area_town", $.proxy(this.gearTouchStart, this))
                .on("touchmove", ".area_town", $.proxy(this.gearTouchMove, this))
                .on("touchend", ".area_town", $.proxy(this.gearTouchEnd, this))
                .on("touchstart", ".area_place", $.proxy(this.gearTouchStart, this))
                .on("touchmove", ".area_place", $.proxy(this.gearTouchMove, this))
                .on("touchend", ".area_place", $.proxy(this.gearTouchEnd, this))
                .on("touchstart", ".larea_cancel", $.proxy(this.close, this))
                .on("touchstart", ".larea_finish", $.proxy(this.finish, this));
        },

        process: function (data) {
            this.data = data;
            this.render(data);
        },

        loadData: function (data, $this) {
            // 判断是否回显
            if ($this.options.initCode != null) {
                let p1 = data.find(function (x) {
                    return x.code == parseInt($this.options.initCode.substr(0, 2))
                });
                let p2 = p1.areaList.find(function (x) {
                    return x.code == parseInt(PrefixZero($this.options.initCode.substr(0, 4), 12, 0))
                });
                let p3 = p2.areaList.find(function (x) {
                    return x.code == parseInt(PrefixZero($this.options.initCode.substr(0, 6), 12, 0))
                });
                let p4 = 0;
                if (p3 && p3.areaList.length !== 0) {
                    p4 = p3.areaList.find(function (x) {
                        return x.code == parseInt(PrefixZero($this.options.initCode.substr(0, 10), 12, 0))
                    });
                }
                let p5 = 0;
                if (p4 !== 0 && p4.areaList.length !== 0) {
                    p5 = p4.areaList.find(function (x) {
                        return x.code == $this.options.initCode
                    });
                }

                this.$main.find(".area_province").attr("val", data.indexOf(p1));
                this.$main.find(".area_city").attr("val", p1.areaList.indexOf(p2));
                this.$main.find(".area_county").attr("val", p2.areaList.indexOf(p3));
                this.$main.find(".area_town").attr("val", p3 && p3.areaList && p3.areaList.length !== 0 ? p3.areaList.indexOf(p4) : 0);
                this.$main.find(".area_place").attr("val", p4 !== 0 && p4.areaList.length !== 0 ? p4.areaList.indexOf(p5) : 0);

            } else {
                this.$main.find(".area_province").attr("val", this.options.position[0]);
                this.$main.find(".area_city").attr("val", this.options.position[1]);
                this.$main.find(".area_county").attr("val", this.options.position[2]);
                this.$main.find(".area_town").attr("val", this.options.position[3]);
                this.$main.find(".area_place").attr("val", this.options.position[4]);
            }

            this.setGearTooth(data);
        },

        getData: function (callback) {
            let _self = this;
            if (typeof _self.source === "object") {
                _self.data = _self.source;
                callback();
            } else {
                let xhr = new XMLHttpRequest();
                xhr.open("get", _self.source);
                xhr.onload = function (e) {
                    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 0) {
                        let responseData = JSON.parse(xhr.responseText);
                        _self.data = responseData.data;
                        if (callback) {
                            callback()
                        }
                    }
                }
                xhr.send();
            }
        },

        gearTouchStart: function (e) {
            e.preventDefault();
            let target = e.target;
            while (true) {
                if (!target.classList.contains("gear")) {
                    target = target.parentElement;
                } else {
                    break
                }
            }
            clearInterval(target["int_" + target.id]);
            target["old_" + target.id] = e.originalEvent.targetTouches[0].screenY;
            // target["old_" + target.id] = e.targetTouches[0].screenY;
            target["o_t_" + target.id] = (new Date()).getTime();
            let top = target.getAttribute("top");
            if (top) {
                target["o_d_" + target.id] = parseFloat(top.replace(/em/g, ""));
            } else {
                target["o_d_" + target.id] = 0;
            }
            target.style.webkitTransitionDuration = target.style.transitionDuration = "0ms";
        },

        gearTouchMove: function (e) {
            e.preventDefault();
            let target = e.target;
            while (true) {
                if (!target.classList.contains("gear")) {
                    target = target.parentElement;
                } else {
                    break
                }
            }
            target["new_" + target.id] = e.originalEvent.targetTouches[0].screenY;
            target["n_t_" + target.id] = (new Date()).getTime();
            let f = (target["new_" + target.id] - target["old_" + target.id]) * 9 / window.innerHeight;
            target["pos_" + target.id] = target["o_d_" + target.id] + f;
            target.style["-webkit-transform"] = "translate3d(0," + target["pos_" + target.id] + "em,0)";
            target.setAttribute("top", target["pos_" + target.id] + "em");
            if (e.originalEvent.targetTouches[0].screenY < 1) {
                this.gearTouchEnd(e);
            }
        },

        gearTouchEnd: function (e) {
            e.preventDefault();
            let target = e.target;
            while (true) {
                if (!target.classList.contains("gear")) {
                    target = target.parentElement;
                } else {
                    break;
                }
            }
            let flag = (target["new_" + target.id] - target["old_" + target.id]) / (target["n_t_" + target.id] - target["o_t_" + target.id]);
            if (Math.abs(flag) <= 0.2) {
                target["spd_" + target.id] = (flag < 0 ? -0.08 : 0.08);
            } else {
                if (Math.abs(flag) <= 0.5) {
                    target["spd_" + target.id] = (flag < 0 ? -0.16 : 0.16);
                } else {
                    target["spd_" + target.id] = flag / 2;
                }
            }
            if (!target["pos_" + target.id]) {
                target["pos_" + target.id] = 0;
            }

            this.rollGear(target);
        },

        rollGear: function rollGear(target, code) {
            let d = 0;
            let stopGear = false;

            function setDuration() {
                target.style.webkitTransitionDuration = target.style.transitionDuration = "500ms";
                stopGear = true;
            }

            let self = this;
            clearInterval(target["int_" + target.id]);
            target["int_" + target.id] = setInterval(function () {
                    let pos = target["pos_" + target.id];
                    let speed = target["spd_" + target.id] * Math.exp(-0.01 * d);
                    pos += speed;
                    if (Math.abs(speed) > 0.1) {
                    } else {
                        let b = Math.round(pos / 3) * 3;
                        pos = b;
                        setDuration();
                    }
                    if (pos > 0) {
                        pos = 0;
                        setDuration();
                    }
                    let len = $(target).data("len");
                    let minTop = -(len - 1) * 3;
                    if (pos < minTop) {
                        pos = minTop;
                        setDuration();
                    }
                    if (stopGear) {
                        let gearVal = Math.abs(pos) / 3;
                        self.setGear(target, gearVal, code);
                        clearInterval(target["int_" + target.id]);
                    }
                    target["pos_" + target.id] = pos;
                    target.style["-webkit-transform"] = "translate3d(0," + pos + "em,0)";
                    target.setAttribute("top", pos + "em");
                    d++;
                },
                30);
        },

        setGear: function (target, val, code) {
            val = Math.round(val);
            $(target).attr("val", val);
            switch (this.options.type) {
                case 1:
                    this.setGearTooth(this.data);
                    break;
                case 2:
                    switch (target.dataset["areatype"]) {
                        case "area_province":
                            this.setGearTooth(_self.data[0]);
                            break;
                        case "area_city":
                            let ref = target.childNodes[val].getAttribute("ref");
                            let childData = [];
                            let nextData = _self.data[2];
                            for (let i in nextData) {
                                if (i === ref) {
                                    childData = nextData[i];
                                    break;
                                }
                            }
                            this.index = 2;
                            this.setGearTooth(childData);
                            break;
                    }
                    break;
            }
        },

        setGearTooth: function (data) {
            let _self = this;
            let item = data || [];
            let l = item.length;
            let gearChild = this.$main.find(".gear");
            if ($(gearChild[_self.index]).attr("val") === undefined || $(gearChild[_self.index]).attr("val") === "NaN") {
                return false;
            }
            let gearVal = $(gearChild[_self.index]).attr("val");
            let maxVal = l - 1;
            if (gearVal > maxVal) {
                gearVal = maxVal;
            }
            $(gearChild[_self.index]).data("len", l);
            if (l > 0) {
                let id = item[gearVal][this.options.keys["id"]];
                let childData;
                switch (_self.options.type) {
                    case 1:
                        childData = item[gearVal].areaList;
                        break;
                    case 2:
                        let nextData = _self.data[_self.index + 1];
                        for (let i in nextData) {
                            if (i === id) {
                                childData = nextData[i];
                                break;
                            }
                        }
                        break;
                }
                let itemStr = "";
                for (let i = 0; i < l; i++) {
                    itemStr += "<div class='tooth'  ref='" + item[i][this.options.keys['id']] + "'>" + item[i][this.options.keys['name']] + "</div>";
                }
                gearChild[_self.index].innerHTML = itemStr;
                gearChild[_self.index].style["-webkit-transform"] = "translate3d(0," + (-gearVal * 3) + "em,0)";
                gearChild[_self.index].setAttribute("top", -gearVal * 3 + "em");
                gearChild[_self.index].setAttribute("val", gearVal);
                $(gearChild[_self.index]).find(".tooth").css("color", "#8e8e8e");
                $(gearChild[_self.index]).find(".tooth")[gearVal].style["color"] = "#000000";

                _self.index++;
                if (_self.index > 4) {
                    _self.index = 0;
                    return;
                }
                _self.setGearTooth(childData);
            } else {
                gearChild[_self.index].innerHTML = "<div class='tooth'></div>";
                gearChild[_self.index].setAttribute("val", 0);
                if (_self.index === 1) {
                    gearChild[2].innerHTML = "<div class='tooth'></div>";
                    gearChild[2].setAttribute("val", 0);
                }
                _self.index = 0;
            }

        },

        finish: function (e) {

            // 点击确认后，清空
            this.options.initCode = null;
            this.options.initName = null;

            let area_province = this.$main.find(".area_province");
            let area_city = this.$main.find(".area_city");
            let area_county = this.$main.find(".area_county");
            let area_town = this.$main.find(".area_town");
            let area_place = this.$main.find(".area_place");

            let provinceVal = parseInt($(area_province).attr("val"));
            let provinceText = $(area_province).find(".tooth")[provinceVal].textContent;
            let provinceCode = $(area_province).find(".tooth")[provinceVal].getAttribute("ref");

            let cityVal = parseInt($(area_city).attr("val"));
            let cityText = $(area_city).find(".tooth")[cityVal].textContent;
            let cityCode = $(area_city).find(".tooth")[cityVal].getAttribute("ref");

            let countyVal = parseInt($(area_county).attr("val"));
            let countyText = $(area_county).find(".tooth")[countyVal].textContent;
            let countyCode = $(area_county).find(".tooth")[countyVal].getAttribute("ref");

            let townVal = parseInt($(area_town).attr("val"));
            let townText = $(area_town).find(".tooth")[townVal].textContent;
            let townCode = $(area_town).find(".tooth")[townVal].getAttribute("ref");

            let placeVal = parseInt($(area_place).attr("val"));
            let placeText = "";
            let placeCode = "";
            if ($(area_place).find(".tooth").length !== 0) {
                placeText = $(area_place).find(".tooth")[placeVal].textContent;
                placeCode = $(area_place).find(".tooth")[placeVal].getAttribute("ref");
            }

            let text = provinceText + (cityText ? " " + cityText : "") + (countyText ? " " + countyText : "") + (townText ? " " + townText : "") + (placeText ? " " + placeText : "");
            this.$element.find("span").text(text);
            let code = provinceCode + (cityCode ? "-" + cityCode : "") + (countyCode ? "-" + countyCode : "") + (townCode ? "-" + townCode : "") + (placeCode ? "-" + placeCode : "");
            this.$element.find("span").data("id", code);
            this.options.position = [provinceVal, cityVal, countyVal, townVal, placeVal];
            this.close(e);
            this.afterSelect(this.$element, code, text);
        },

        initValue: function () {
            // 判断是否有初始值
            if (this.options.initCode != null) {
                // 定义一个code变量
                let cd = '';
                // 切分省市区
                cd = this.options.initCode.substr(0, 2) + '-';
                cd = cd + PrefixZero(this.options.initCode.substr(0, 4), 12, 0) + '-';
                cd = cd + PrefixZero(this.options.initCode.substr(0, 6), 12, 0);

                if (this.options.initCode.substr(6, 6) != '000000') {
                    cd = cd + '-' + this.options.initCode;
                }

                this.$element.find("span").text(this.options.initName);
                this.$element.find("span").data("id", cd);
                this.afterSelect(this.$element, this.options.initCode, this.options.initName);
            }
        },

        close: function (e) {
            e.preventDefault();
            this.$main.detach();
        }
    };

    let old = $.fn.h5CityPicker;

    $.fn.h5CityPicker = function (options) {
        return new H5CityPicker(this, options);
    };

    $.fn.h5CityPicker.defaults = {
        main: "<div class='gearArea'>" +
        "           <div class='area_ctrl slideInUp'>" +
        "               <div class='area_btn_box'>" +
        "                   <div class='area_btn larea_cancel'>取消</div>" +
        "                   <div class='area_btn larea_finish'>确定</div>" +
        "               </div>" +
        "               <div class='area_roll_mask'>" +
        "                   <div class='area_roll'>" +
        "                       <div>" +
        "                           <div class='gear area_province' data-areatype='area_province'></div>" +
        "                           <div class='area_grid'></div>" +
        "                       </div>" +
        "                       <div>" +
        "                           <div class='gear area_city' data-areatype='area_city'></div>" +
        "                           <div class='area_grid'></div>" +
        "                       </div>" +
        "                       <div>" +
        "                           <div class='gear area_county' data-areatype='area_county'></div>" +
        "                           <div class='area_grid'></div>" +
        "                       </div>" +
        "                       <div>" +
        "                           <div class='gear area_town' data-areatype='area_town'></div>" +
        "                           <div class='area_grid'></div>" +
        "                       </div>" +
        "                       <div>" +
        "                           <div class='gear area_place' data-areatype='area_place'></div>" +
        "                           <div class='area_grid'></div>" +
        "                       </div>" +
        "                   </div>" +
        "               </div>" +
        "           </div>" +
        "       </div>",
        keys: {
            id: "code",
            name: "name"
        }, // 绑定数据源相关字段 id对应valueTo的value属性输出 name对应trigger的value属性输出
        type: 1, // 数据源类型
        position: [0, 0, 0, 0, 0],
        afterSelect: $.noop,
        direct: false,
        initCode: null,
        initName: null
    };

    $.fn.h5CityPicker.Constructor = H5CityPicker;

    $.fn.h5CityPicker.noConflict = function () {
        $.fn.h5CityPicker = old;
        return this;
    };

    // 补0方法
    PrefixZero = function (str, num, n) {
        var s = str + '';
        return s + new Array(num - s.length + 1).join(n);
    }
}));
